package com.hejia.alauda.service;

import com.alibaba.fastjson.JSONObject;
import com.hejia.alauda.entity.*;
import com.hejia.alauda.entity.CreditOperation.Operation;
import com.hejia.alauda.entity.example.*;
import com.hejia.alauda.mongodb.Activation;
import com.hejia.alauda.mongodb.IwxTicket;
import com.hejia.alauda.persistence.mybatis.*;
import com.hejia.alauda.utils.DateTimeUtil;
import com.hejia.alauda.utils.Pager;
import com.hejia.alauda.utils.Utils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import static com.hejia.alauda.utils.RateUtil.getDate;
import static com.hejia.alauda.utils.Utils.formatDate;
import static org.apache.commons.lang3.time.DateFormatUtils.ISO_DATE_FORMAT;
import static org.apache.commons.lang3.time.DateUtils.*;
import static org.springframework.util.CollectionUtils.isEmpty;
import static org.apache.commons.lang3.StringUtils.*;

/**
 * 积分有关的service
 * 
 * @author paul
 *
 */
@Service
public class CreditServiceImpl implements CreditService {

	private final Log logger = LogFactory.getLog(getClass());

	@Resource
	private DuibaOrderMapper duibaOrderMapper;

	protected static int MONEY_TO_CREDIT = 100;// 购买金额转换成积分的比率（暂时1000元1积分）
	protected static int DAY_CREDIT = 1;// 日积分

	@Resource
	private QualificationMapper qualificationMapper;

	@Resource
	private CreditMapper creditMapper;

	@Resource
	private CreditOperationMapper creditOperationMapper;

	@Resource
	private BankCardMapper bankCardMapper;

	@Resource
	private FinancingMapper financingMapper;

	@Resource
	protected PopularizeService popularizeService;

	@Resource
	private CommonService commonService;

	@Resource
	BonusRecordMapper bonusRecordMapper;

	@Resource
	BonusOrderMapper bonusOrderMapper;

	@Resource
	RedEnvelopeService redEnvelopeService;

	@Resource
	UserService userService;

	@Resource
	private MongoTemplate mongoTemplate;

	@Resource
	PaymentService paymentService;

	@Resource
	ConfigureService configureService;

	@Override
	@Transactional
	public boolean calculateProductCredits(Financing financing) {
		int credits = 0;
		if (financing != null) {
			double amount = financing.getAmount().doubleValue();
			// 只有满100元才开始计算积分
			if (amount / MONEY_TO_CREDIT >= 1) {
				JSONObject config = new JSONObject(
						configureService.getActivityConfig("SYSTEM_CONFIG"))
						.getJSONObject("config");
				double rate = config.getDoubleValue("creditRate");
				credits = (int) Math.floor(amount / 100 * financing.getTerm()
						* rate);
				addCreditOperation(credits, financing.getUser(),
						CreditOperation.Operation.BUY, "购买["
								+ financing.getProduct().getName() + "]赠送积分");
			}
		}
		return true;
	}

	@Override
	public Credit findCreditByUserId(Long id) {
		return creditMapper.selectByPrimaryKey(id);
	}

	@Override
	public int sumTodayCredits(Long id) {
		int credits = 0;
		CreditOperationExample example = new CreditOperationExample();
		example.appendCriterion("user_id=", id);
		List<CreditOperation> list = creditOperationMapper.selectByExample(
				example, null);
		if (!isEmpty(list)) {
			String now = ISO_DATE_FORMAT.format(Calendar.getInstance());
			for (CreditOperation item : list) {
				if (now.equals(ISO_DATE_FORMAT.format(item.getCreateDate()))) {
					credits += (item.getCreditChanges().intValue() < 0) ? 0
							: item.getCreditChanges();
				}
			}
		}
		return credits;
	}

	@Override
	public List<CreditOperation> findCreditOperationsByUser(User user) {
		CreditOperationExample example = new CreditOperationExample();
		example.appendCriterion("user_id=", user.getId());
		example.setOrderByClause("createDate desc");
		return this.creditOperationMapper.selectByExample(example, null);
	}

	@Override
	public Pager<CreditOperation> findCreditOperationsByPager(
			CreditOperationExample example, Pager<CreditOperation> pager) {
		if (pager != null) {
			pager.setList(creditOperationMapper.selectByExample(example, pager));
			pager.setTotalCount(creditOperationMapper.countByExample(example));
		}
		return pager;
	}

	@Override
	public int updateCredit(Credit record) {
		return creditMapper.updateByPrimaryKey(record);
	}

	@Override
	public int insertCreditOperation(CreditOperation record) {
		return creditOperationMapper.insert(record);
	}

	@Transactional
	@Override
	public boolean addCreditOperation(Integer credits, User user,
			Operation operation, String description) {
		Credit credit = this.creditMapper.selectByPrimaryKey(user.getId());
		credits = credits != null ? credits : 0;

		Map<String, Object> params = new HashMap<String, Object>();
		params.put("credits", credits);
		params.put("id", credit.getId());

		creditMapper.updateCredit(params);

		// 增加积分变动记录
		CreditOperation creditOperation = new CreditOperation();
		creditOperation.setCreateDate(getDate());
		creditOperation.setModifyDate(creditOperation.getCreateDate());
		creditOperation.setUser(user);
		creditOperation.setCreditChanges(credits);
		creditOperation.setDescription(description);
		creditOperation.setOperation(operation);

		return creditOperationMapper.insert(creditOperation) > 0;
	}

	@Override
	public int sendRookieCredits(User user, Operation operation) {
		int result = 0;
		if (Utils.formatDateTime(user.getCreateDate()).compareTo(
				Utils.redenvelopeEndTime) >= 0) {
			switch (operation) {
			case REGISTER:
				this.addCreditOperation(Utils.REGISTER_CREDITS, user,
						CreditOperation.Operation.REGISTER, "注册赠送积分");
				break;
			case BIND:
				// 判读是否第一次绑卡
				BankCardExample example = new BankCardExample();
				example.appendCriterion("user_id=", user.getId());
				example.appendCriterion("status=", BankCard.Status.BINDED);

				CreditOperationExample coExample = new CreditOperationExample();
				coExample.appendCriterion("user_id=", user.getId());
				coExample.appendCriterion("operation=",
						CreditOperation.Operation.BIND.toString());
				if (bankCardMapper.countByExample(example) == 1
						&& creditOperationMapper.countByExample(coExample) == 0) {
					// 首次绑卡赠送积分(如果是2015-02-01T00:00:00之前的)
					addCreditOperation(Utils.BIND_CARD_CREDITS, user,
							CreditOperation.Operation.BIND, "首次绑卡赠送积分");
				}
				break;
			default:
				break;
			}
		}
		return result;
	}

	@Override
	public Pager<CreditOperation> recentChanges(Pager<CreditOperation> pager) {
		CreditOperationExample example = new CreditOperationExample();
		example.setOrderByClause("`createDate` desc");
		List<CreditOperation> list = creditOperationMapper.selectByExample(
				example, pager);
		int total = creditOperationMapper.countByExample(example);
		pager.setList(list);
		pager.setTotalCount(total);
		return pager;
	}

	@Override
	public Pager<CreditOperation> findManualCredit(Pager<CreditOperation> pager) {
		return findManualCredit(pager, new CreditOperationExample());
	}

	@Override
	public Pager<CreditOperation> findManualCredit(
			Pager<CreditOperation> pager, CreditOperationExample example) {
		example.appendCriterion("operation=", CreditOperation.Operation.MANUAL);
		example.setOrderByClause("id desc");
		pager.setList(creditOperationMapper.selectByExample(example, pager));
		pager.setTotalCount(creditOperationMapper.countByExample(example));
		return pager;
	}

	@Override
	public int insertDuibaOrder(DuibaOrder record) {
		return duibaOrderMapper.insert(record);
	}

	@Override
	public int dealExchangeResult(Integer status, String orderNum) {
		return duibaOrderMapper.dealExchangeResult(status, orderNum);
	}

	@Override
	public DuibaOrder findDuibaOrderByExample(DuibaOrderExample example) {
		return duibaOrderMapper.selectOneByExample(example);
	}

	@Override
	public boolean giveBonus(Long userId, String code, int term,
			BigDecimal amount, String description, String type, String operator) {
		Redpacket red = redEnvelopeService.getRedpacketByCode(code);
		BonusRecord record = new BonusRecord();
		if (amount == null) {
			record.setAmount(new BigDecimal(red.getValue()));
		} else {
			record.setAmount(amount);
		}
		record.setDescription(description);
		record.setType(type);
		record.setCode(code);
		record.setConsume(false);
		record.setUser(userService.findUserById(userId));
		record.setRemaining(record.getAmount());
		record.setCreateDate(Calendar.getInstance().getTime());
		record.setModifyDate(record.getCreateDate());
		record.setOperator(operator);
		if (term == 0) {
			record.setExpiredDate(DateTimeUtil.getDateDay(red.getInvalidDate()));
		} else {
			record.setExpiredDate(DateUtils.addDays(record.getCreateDate(),
					term));
		}
		return bonusRecordMapper.insert(record) > 0;
	}

	@Override
	public int countQualificationByExample(QualificationExample example) {
		return qualificationMapper.countByExample(example);
	}

	@Override
	public Pager<BonusRecord> findBonusRecordListByPager(
			Map<String, Object> params, Pager<BonusRecord> pager) {
		pager.setList(bonusRecordMapper.findBonusRecordsByPager(params, pager));
		pager.setTotalCount(bonusRecordMapper
				.findBonusRecordsCountByPager(params));
		// pager.setList(bonusRecordMapper.selectByExample(example, pager));
		// pager.setTotalCount(bonusRecordMapper.countByExample(example));
		return pager;
	}

	@Override
	public BonusRecord findBonusRecordById(Long id) {
		return bonusRecordMapper.selectByPrimaryKey(id);
	}

	@Override
	public BonusOrder findBonusOrderByBonusRecord(BonusRecord bonusRecord) {
		return bonusOrderMapper.findBonusOrderByBonusRecord(bonusRecord);
	}

	@Override
	public void createActivation(String orderNumber, Long bonusRecord_id) {
		Activation activation = new Activation();
		activation.setId(new ObjectId());
		activation.setCreateDate(Utils.formatDateTime(Calendar.getInstance()));
		activation.setModifyDate(activation.getCreateDate());
		activation.setOrderNumber(orderNumber);
		activation.setBonusRecord_id(bonusRecord_id);
		activation.setEnabled(false);
		mongoTemplate.save(activation);
	}

	@Override
	public void activateBonusRecord(Order order) {
		Date now = Calendar.getInstance().getTime();
		List<Activation> activations = mongoTemplate.find(new Query(
				new Criteria("orderNumber").is(order.getOrderNumber())),
				Activation.class);
		if (!isEmpty(activations)) {
			for (Activation activation : activations) {
				// 判断该红包是否被回调激活过
				BonusOrderExample example = new BonusOrderExample();
				example.appendCriterion("bonusRecord_id=",
						activation.getBonusRecord_id());
				if (bonusOrderMapper.countByExample(example) == 0) {
					if (!activation.getEnabled()) {
						activation.setEnabled(true);
						mongoTemplate.save(activation);

						BonusRecord bonusRecord = bonusRecordMapper
								.selectByPrimaryKey(activation
										.getBonusRecord_id());
						if (bonusRecord != null) {
							Map<String, Object> params = new HashMap<String, Object>();
							params.put("id", bonusRecord.getId());
							params.put("consume", Boolean.TRUE);
							params.put("consumeDate", now);
							params.put("remaining", 0);
							bonusRecordMapper.updateConsumeById(params);

							BonusOrder bonusOrder = new BonusOrder();
							bonusOrder.setCreateDate(now);
							bonusOrder.setModifyDate(now);
							bonusOrder.setAmount(bonusRecord.getAmount());
							bonusOrder.setBonusRecord(bonusRecord);
							bonusOrder.setOrder(order);
							bonusOrder.setRepaid(Boolean.FALSE);
							bonusOrderMapper.insert(bonusOrder);
							try {
								paymentService.applyBonusRepay(bonusOrder
										.getId());
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
					}
				}
			}
		}
	}

	@Override
	public List<BonusRecord> bonusRecordPager(Pager<BonusRecord> pager) {
		BonusRecordExample example = new BonusRecordExample();
		example.setOrderByClause("id desc");
		List<BonusRecord> list = bonusRecordMapper.selectByExample(example,
				pager);
		int total = bonusRecordMapper.countByExample(example);
		pager.setTotalCount(total);
		pager.setList(list);
		return list;
	}

	@Override
	public BigDecimal findBonusAmount(Map<String, Object> bonusExample) {
		return bonusRecordMapper.amountCountByExample(bonusExample);
	}

	@Override
	public Pager<BonusRecord> findBonusRecordPager(BonusRecordExample example,
			Pager<BonusRecord> pager, boolean isPagination) {
		if (!isPagination) {
			pager.setList(bonusRecordMapper.selectByExample(example, null));
		} else {
			pager.setList(bonusRecordMapper.selectByExample(example, pager));
			pager.setTotalCount(bonusRecordMapper.countByExample(example));
		}
		return pager;
	}

	@Override
	public int updateReadByUser(Long id) {
		return this.bonusRecordMapper.updateReadByUser(id);
	}

	@Override
	public int removeRegisterBonusRecord(Long id) {
		return this.bonusRecordMapper.removeRegisterBonusRecord(id);
	}

	@Override
	public void insertRandomBonusRecord(User user, String redcode) {
		if (isNotBlank(redcode)) {
			IwxTicket ticket = mongoTemplate.findOne(new Query(new Criteria(
					"code").is(redcode).and("type").is("RedCode")),
					IwxTicket.class);
			if (ticket != null && !ticket.isUsed()) {
				ticket.setUsed(true);
				ticket.setMobile(user.getMobile());
				mongoTemplate.save(ticket);

				BonusRecord record = new BonusRecord();
				record.setAmount(new BigDecimal(ticket.getValue()));
				record.setExpiredDate(addDays(user.getCreateDate(), 3));
				record.setDescription("爱客仕赠送了" + record.getAmount() + "元的红包");
				record.setType("REDPACKET_XPOS");
				record.setCode("REDPACKET_XPOS");
				record.setConsume(false);
				record.setUser(user);
				record.setRemaining(record.getAmount());
				record.setCreateDate(user.getCreateDate());
				record.setModifyDate(user.getCreateDate());
				bonusRecordMapper.insert(record);
			}
		}
	}

	@Override
	public int countUnusedBonusRecordByUser(User user) {
		if (user != null) {
			BonusRecordExample example = new BonusRecordExample();
			example.appendCriterion("DATE(`expiredDate`)>=",
					formatDate(java.util.Calendar.getInstance()));
			example.appendCriterion("`consume`=", false);
			example.appendCriterion("`user_id`=", user.getId());
			return this.bonusRecordMapper.countByExample(example);
		}
		return 0;
	}

}
